package com.rookieci.lifegame.game;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.rookieci.lifegame.MyApp;
import com.rookieci.lifegame.SpUtils;

import java.util.Random;

public class GameView extends SurfaceView implements SurfaceHolder.Callback {
    public GameView(@NonNull Context context) {
        super(context);
        initHolder();
    }

    public GameView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initHolder();
    }

    public GameView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initHolder();
    }

    public GameView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initHolder();
    }

    private void initHolder() {
        size = SpUtils.getInstance().getSize();
        SurfaceHolder holder = getHolder();
        holder.addCallback(this);
    }

    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
        Log.d("GameView", "surfaceCreated");
        this.holder = holder;
        runThread();
    }

    @Override
    public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
        Log.d("GameView", "surfaceChanged,width:" + width);
        Log.d("GameView", "surfaceChanged,height:" + height);
        this.holder = holder;
        this.width = width;
        this.height = height;
        runThread();
    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
        Log.d("GameView", "surfaceDestroyed");
        this.holder = null;
    }

    private void runThread() {
        if (holder == null) return;
        runnable = new Runnable() {
            @Override
            public void run() {
                if (runnable == null || runnable != this) return;
                drawGame();
                runThread();
            }
        };
        MyApp.getInstance().runThread(runnable, 100);
    }

    private Runnable runnable;
    private int size;
    private int width, height;
    private SurfaceHolder holder;
    private Paint linePaint;
    private Paint rectPaint;
    private GameMode[][] gameModes;
    private int wNumb;
    private int hNumb;
    private boolean isPause;
    private final Random random = new Random();

    public boolean isPause() {
        return isPause;
    }

    public void pause() {
        isPause = true;
        /*生成一个方块
        synchronized (GameView.class) {
            for (int i = 1; i < 4; i++) {
                for (int j = 1; j < 4; j++) {
                    GameMode gameMode = gameModes[i][j];
                    if (gameMode == null) {
                        gameModes[i][j] = gameMode = new GameMode();
                    }
                    gameMode.live = true;
                }
            }
        }*/
    }

    public void resume() {
        isPause = false;
    }

    public void addMode() {
        if (!isPause) return;
        int i = wNumb / 10;
        int j = hNumb / 10;
        int numb = Math.max(i, 1) * Math.max(j, 1);
        synchronized (GameView.class) {
            for (int k = 0; k < numb; k++) {
                int x = random.nextInt(wNumb);
                int y = random.nextInt(hNumb);
                GameMode gameMode = gameModes[y][x];
                if (gameMode == null) {
                    gameMode = gameModes[y][x] = new GameMode();
                }
                gameMode.live = true;
            }
        }
    }

    private void drawGame() {
        if (holder == null || width == 0 || height == 0) return;
        Canvas canvas;
        int left, top;
        Surface surface = holder.getSurface();
        synchronized (GameView.class) {
            if (gameModes == null) {//线条2像素
                wNumb = (width + 2) / (size + 2);
                hNumb = (height + 2) / (size + 2);
                gameModes = new GameMode[hNumb][wNumb];
            }
            if (!isPause) {
                //统计数量
                for (int x = 0; x < wNumb; x++) {
                    for (int y = 0; y < hNumb; y++) {
                        GameMode gameMode = gameModes[y][x];
                        if (gameMode == null) {
                            gameModes[y][x] = gameMode = new GameMode();
                        }
                        for (int i = Math.max(0, x - 1); i <= x + 1; i++) {
                            if (i >= wNumb) continue;
                            for (int j = Math.max(0, y - 1); j <= y + 1; j++) {
                                if (j >= hNumb) continue;
                                if (i == x && j == y) continue;
                                GameMode mode = gameModes[j][i];
                                boolean live = mode != null && mode.live;
                                if (live) {
                                    gameMode.liveNumb++;
                                }
                            }
                        }
                    }
                }
                //输出
                /*for (int y = 0; y < hNumb; y++) {
                    StringBuilder builder = new StringBuilder();
                    for (int x = 0; x < wNumb; x++) {
                        GameMode gameMode = gameModes[y][x];
                        if (gameMode == null) {
                            gameModes[y][x] = gameMode = new GameMode();
                        }
                        builder.append('[')
                                .append(gameMode.liveNumb)
                                .append(']');
                    }
                    Log.v("-xcc-", "-->" + builder);
                }*/
                //改变状态
                for (int x = 0; x < wNumb; x++) {
                    for (int y = 0; y < hNumb; y++) {
                        GameMode gameMode = gameModes[y][x];
                        int liveNumb = gameMode.liveNumb;
                        //(1)当前细胞为死亡状态时，当周围有3个存活细胞时，则迭代后该细胞变成存活状态(模拟繁殖)；若原先为生，则保持不变。
                        //(2)当前细胞为存活状态时，当周围的邻居细胞低于两个(不包含两个)存活时，该细胞变成死亡状态(模拟生命数量稀少)。
                        //(3)当前细胞为存活状态时，当周围有两个或3个存活细胞时，该细胞保持原样。
                        //(4)当前细胞为存活状态时，当周围有3个以上的存活细胞时，该细胞变成死亡状态(模拟生命数量过多)。
                        if (gameMode.live) {
                            if (liveNumb < 2 || liveNumb > 3) {
                                gameMode.live = false;
                            }
                        } else if (liveNumb == 3) {
                            gameMode.live = true;
                        }
                        gameMode.liveNumb = 0;
                    }
                }
            }
            left = (width + 2 - wNumb * (size + 2)) >>> 1;
            top = (height + 2 - hNumb * (size + 2)) >>> 1;

            canvas = surface.lockCanvas(null);
            if (canvas == null) return;
            canvas.drawColor(-1);
            for (int x = 0; x < wNumb; x++) {
                for (int y = 0; y < hNumb; y++) {
                    GameMode gameMode = gameModes[y][x];
                    boolean live = gameMode != null && gameMode.live;
                    int startX = left + (size + 2) * x - 2;
                    int startY = top + (size + 2) * y - 2;
                    canvas.drawRect(startX, startY, startX + size, startY + size, getRectPaint(live));
                }
            }
        }
        for (int i = 0; i <= wNumb; i++) {
            int startX = left + (size + 2) * i - 2;
            canvas.drawLine(startX, top, startX, height - top, getLinePaint());
        }
        for (int i = 0; i <= hNumb; i++) {
            int startY = top + (size + 2) * i - 2;
            canvas.drawLine(left, startY, width - left, startY, getLinePaint());
        }
        surface.unlockCanvasAndPost(canvas);
    }

    private Paint getLinePaint() {
        if (linePaint == null) {
            linePaint = new Paint();
            linePaint.setColor(0xFFDDddDD);
            linePaint.setStrokeWidth(2);
            linePaint.setStyle(Paint.Style.FILL);
        }
        return linePaint;
    }

    private Paint getRectPaint(boolean live) {
        if (rectPaint == null) {
            rectPaint = new Paint();
        }
        rectPaint.setColor(live ? 0xFF333333 : -1);
        return rectPaint;
    }
}
